/**
 * 
 */
package it.uniroma3.dia.digraph.algorithm.kouterplanar.kouterplanar;

import it.uniroma3.dia.digraph.algorithm.utility.Utility;
import it.uniroma3.dia.digraph.algorithm.utility.stackedtri.StackedTriNode;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.graphdrawing.graphml.xmlns.NodeType;

/**
 * @author Cionzo
 *
 */
public class KouterplanarNode extends StackedTriNode{
    
    private NodeType node;
    private boolean arrived;
    private Map<KouterplanarNode, Double> parent2lambda;
    private int depth;

    /**
     * @param node
     */
    public KouterplanarNode(NodeType node) {
	
	this.node = node;
	this.arrived = false;
	this.parent2lambda = null;
    }
    
    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
	if (this == obj)
	    return true;
	if (obj == null)
	    return false;
	if (getClass() != obj.getClass())
	    return false;
	KouterplanarNode other = (KouterplanarNode) obj;
	if (node == null) {
	    if (other.node != null)
		return false;
	} else if (!node.equals(other.node))
	    return false;
	return true;
    }
    
    /**
     * @return the node
     */
    public NodeType getNode() {
        return node;
    }
    
    /**
     * @return the parent2lambda
     */
    public Map<KouterplanarNode, Double> getParent2lambda() {
        return parent2lambda;
    }
    
    /**
     * @return
     */
    private double getParentXcombination() {
	double x = 0;
	for (KouterplanarNode parent : this.parent2lambda.keySet())
	    x += parent.getNode().getX() * this.parent2lambda.get(parent);
	
	return x;
    }

    /**
     * @return
     */
    private double getParentYcombination() {
	double y = 0;
	for (KouterplanarNode parent : this.parent2lambda.keySet())
	    y += parent.getNode().getY() * this.parent2lambda.get(parent);
	
	return y;
    }

    /**
     * @return the x coordinate
     */
    public double getX() {
//	if (! this.arrived)
	if (this.depth!=0)
	    this.node.setX(this.getParentXcombination());
	
	return this.node.getX();
    }

    /**
     * @return the y coordinate
     */
    public double getY() {
//	if (! this.arrived)
	if (this.depth!=0)
	    this.node.setY(this.getParentYcombination());
	
	return this.node.getY();
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + ((node == null) ? 0 : node.hashCode());
	return result;
    }

    /**
     * @return the arrived
     */
    public boolean isArrived() {
        return arrived;
    }

    /**
     * @param arrived the arrived to set
     */
    public void setArrived(boolean arrived) {
        this.arrived = arrived;
    }

    /**
     * @param node the node to set
     */
    public void setNode(NodeType node) {
        this.node = node;
    }

    /**
     * @param parent2lambda the parent2lambda to set
     */
    public void setParent2lambda(Map<KouterplanarNode, Double> parent2lambda) {
        this.parent2lambda = parent2lambda;
    }

    /**
     * @param parents
     * @param adjacencyMatrix 
     */
    public void setParentAndLambdas(List<KouterplanarNode> parents, Map<String, Set<String>> adjacencyMatrix) {
	List<NodeType> parentNodes = new LinkedList<NodeType>();
	Map<String, Set<String>> adjModMatrix = new HashMap<String, Set<String>>();
	Set<String> boundaryNeighbors;
	Set<String> ids = new HashSet<String>();
	Map<String, KouterplanarNode> nodeMap = new HashMap<String, KouterplanarNode>();
	for (KouterplanarNode node : parents)
	    ids.add(node.getNode().getId());
	
	for (KouterplanarNode kparent : parents) {
	    	nodeMap.put(kparent.getNode().getId(), kparent);
	    	parentNodes.add(kparent.getNode());
	    	boundaryNeighbors = new HashSet<String>(adjacencyMatrix.get(kparent.getNode().getId()));
	    	boundaryNeighbors.retainAll(ids);
	    	
	    	adjModMatrix.put(kparent.getNode().getId(), boundaryNeighbors);
	}	
	
	List<NodeType> ccwNeighborsNodes = Utility.getBoundary(parentNodes, adjModMatrix);
	parents.clear();
	for (NodeType node : ccwNeighborsNodes)
	    parents.add(nodeMap.get(node.getId()));	
	
	
	
	this.parent2lambda = Utility.homogeneusCoords(this, parents);
//	System.out.println(this.node.getId()+": "+this.parent2lambda);
	
    }

    /**
     * @param x
     */
    public void setX(double x) {
	this.node.setX(x);
    }

    /**
     * @param y
     */
    public void setY(double y) {
	this.node.setY(y);
    }
    
    public String toString() {
	return this.node.toString();
    }

    /**
     * @param depth the depth to set
     */
    public void setDepth(int depth) {
	this.depth = depth;
    }

    /**
     * @return the depth
     */
    public int getDepth() {
	return depth;
    }

}
